1. Introduction > 2. Mon premier projet > 3. Modèle > 4. Vue > 5. Liste de données > 6. Mapping objet/relationnel > 7. Contrôleurs > 8. Application > 9. Personnalisation

Chapitre 5 : Liste de données

Les liste de données sont affichées sous forme de tableaux. Si vous créez un module conventionnel OpenXava, l'utilisateur peut gérer les données du composant avec une liste telle que celle-ci :
tab_en010.jpg
La liste permet à l'utilisateur de
  • filtrer par n'importe quelle colonne et n'importe quelle combinaison de colonnes
  • trier par n'importe quelle colonne sur un simple click
  • afficher les données paginées et ainsi travailler efficacement avec plusieurs millions d'enregistrements
  • personnaliser la liste : ajouter, enlever des colonnes ou encore changer leur ordre (avec le petit crayon situé dans le coin en haut à gauche). Ces personnalisations sont mémorisées pour chaque utilisateur
  • exécuter des actions génériques de traitement des données de la liste : générer des rapports PDF, exporter vers Excel ou supprimer des objets sélectionnés.
La liste par défaut est suffisante pour beaucoup de cas et en plus, l'utilisateur peut la personnaliser. Quoiqu'il en soit, il est parfois pratique de modifier le comportement de la liste. Pour cela, vous bénéficiez de l'annotation @Tab dans la définition d'une entité. La syntaxe de l'annotation @Tab est la suivante :
@Tab(
 name="name", // 1
 filter=filter class, // 2
 rowStyles=array of @RowStyle, // 3
 properties="properties", // 4
 baseCondition="base condition", // 5
 defaultOrder="default order" // 6
)
public class MyEntity {
  1. name (optionnel) : Vous pouvez définir plusieurs listes pour une entité (en utilisant l'annotation @Tabs), et donner un nom à chacune d'elles. Ce nom est utilisé pour indiquer la liste qui doit être utilisée dans un contexte (en général dans le fichier application.xml de votre projet).
  2. filter (optionnel). Permet de définir de manière codée la logique à appliquer aux valeurs entrées par l'utilisateur quand il filtre les données de la liste.
  3. rowStyles (optionnel) : Indique une manière simple de spécifier un style différent pour certaines lignes. Normalement, c'est utilisé pour mettre en évidence les lignes qui répondent à certaines conditions. Vous spécifiez un ensemble d'annotations @RowStyle pour utiliser plusieurs styles dans une liste.
  4. properties (optionnel) : La liste des propriétés affichées initialement. Les propriétés peuvent être qualifiées, c'est-à-dire vous spécifiez nomReference.nomPropriete à n'importe quel niveau de profondeur. Please, translate the next sentence to French: The suffix + (new in v4.1) can be added to a property to show the sum of the column at bottom.
  5. baseCondition (optionnel) : La condition de base qui doit être satisfaite pour qu'une donnée soit affichée. Elle est ajoutée à la condition de l'utilisateur si nécessaire.
  6. defaultOrder (optionnel) : Spécifie le tri initial des données.

Propriétés initiales et mise en évidence des lignes

La personnalisation la plus simple est d'indiquer quelles propriétés doivent être affichées initialement :
@Tab(
 rowStyles=@RowStyle(style="row-highlight", property="type", value="steady"),
 properties="name, type, seller.name, address.city, seller.level.description, address.state.name"
)
Ces propriétés sont affichées la première fois qu'un module est exécuté. Après cela, l'utilisateur à la possibilité de changer les propriétés à afficher. Notez également l'utilisation de propriétés qualifiées (propriétés de références) à n'importe quel niveau de profondeur.
Dans cet exemple, il est également démontré comment utiliser une annotation @RowStyle. Il est dit que l'objet dont la propriété type a une valeur steady utilisera le style row-highlight. Le style doit être défini dans une feuille de style CSS. Le style row-highlight (highlightin versions previous to v4m3) est déjà défini dans OpenXava, mais vous pouvez en ajouter plus, (please, translate to French) but you can define your own styles with the custom.css file in web/xava/style (new in v4.5).
. L'effet visuel de l'exemple ci-dessus est le suivant :
tab_en020.jpg

Filtres et condition de base

Une technique commune est de combiner un filtre avec une condition de base :
@Tab(name="Current",
 filter=CurrentYearFilter.class,
 properties="year, number, amountsSum, vat, detailsCount, paid, customer.name",
 baseCondition="${year} = ?"
)
La condition doit avoir une syntaxe SQL dans laquelle vous pouvez utiliser le point d'interrogation (?) pour les arguments et les noms de propriétés entre ${}. Dans l'exemple, un filtre est utilisé comme valeur de l'argument. Le code du filtre est le suivant :
package org.openxava.test.filters;
 
import java.util.*;
 
import org.openxava.filters.*;
 
/**
 * @author Javier Paniza
 */
 
public class CurrentYearFilter implements IFilter { // (1)
 
 public Object filter(Object o) throws FilterException { // (2)
 Calendar cal = Calendar.getInstance();
 cal.setTime(new java.util.Date());
 Integer year = new Integer(cal.get(Calendar.YEAR));
 Object [] r = null;
 if (o == null) { // (3)
 r = new Object[1];
 r[0] = year;
 }
 else if (o instanceof Object []) { // (4)
 Object [] a = (Object []) o;
 r = new Object[a.length + 1];
 r[0] = year;
 for (int i = 0; i < a.length; i++) {
 r[i+1]=a[i];
 }
 }
 else { // (5)
 r = new Object[2];
 r[0] = year;
 r[1] = o;
 }
 
 return r;
 }
 
}
Un filtre récupère les arguments lorsque l'utilisateur entre des conditions pour filtrer la liste. Pour l'exécution, elle retourne la valeur envoyée à OpenXava pour lancer la requête. Comme vous pouvez le voir, la classe doit implémenter l'interface IFilter, ce qui la force à avoir une méthode filter() (2) qui reçoit l'objet avec la valeur des arguments et retourne la valeur filtrée qui sera utilisée comme argument de la requête. Ces arguments peuvent être null (3) si l'utilisateur n'entre pas de critères, un objet simple (5) si l'utilisateur entre une valeur unique ou un tableau d'objets si l'utilisateur entre plusieurs valeurs. Le filtre doit considérer tous les cas. Le filtre de cet exemple ajoute l'année courante comme premier argument et sa valeur est utilisée pour remplir les arguments définis dans baseCondition de la liste.
Pour résumer, la liste que vous voyez ci-dessus ne montre que les factures (invoices) de l'année en cours.
Un autre cas :
@Tab(name="DefaultYear",
 filter=DefaultYearFilter.class,
 properties="year, number, customer.number, customer.name, amountsSum, " +
 "vat, detailsCount, paid, importance",
 baseCondition="${year} = ?"
)
Dans ce cas, le filtre est celui-ci :
package org.openxava.test.filters;
 
import java.util.*;
 
import org.openxava.filters.*;
 
/**
 * @author Javier Paniza
 */
 
public class DefaultYearFilter extends BaseContextFilter { // (1)
 
 public Object filter(Object o) throws FilterException {
 if (o == null) {
 return new Object [] { getDefaultYear() }; // (2)
 }
 if (o instanceof Object []) {
 List c = new ArrayList(Arrays.asList((Object []) o));
 c.add(0, getDefaultYear()); // (2)
 return c.toArray();
 }
 else {
 return new Object [] { getDefaultYear(), o }; // (2)
 }
 }
 
 private Integer getDefaultYear() throws FilterException {
 try {
 return getInteger("xavatest_defaultYear"); // (3)
 }
 catch (Exception ex) {
 ex.printStackTrace();
 throw new FilterException(
 "Impossible to obtain default year associated with the session");
 }
 }
 
}
Le filtre étend la classe BaseContextFilter, ce qui vous permet d'accéder aux objets de session de OpenXava. Vous pouvez remarquer comment le filtre utilise la méthode getDefaultYear() (2) qui appelle getInteger() (3) qui (comme getString(), getLong() ou plus généralement get()) qui permet d'accéder à la valeur de l'objet de session xavatest_defaultYear. Cet objet est défini dans le fichier controllers.xml de cette manière :
<object name="xavatest_defaultYear" class="java.lang.Integer" value="1999"/>
Les actions peuvent modifier le filtre et son cycle de vie est celui de la session, mais privé pour chaque module. Cette fonctionnalité est traitée plus en profondeur dans le chapitre 7.
C'est une bonne technique pour que l'affichage des données en mode liste dépende de l'utilisateur ou de la configuration qu'il a choisie. Il est également possible d'accéder aux variable d'environnement à partir d'un filtre de type BaseContextFilter, en utilisant la méthode getEnvironment() comme ceci :
new Integer(getEnvironment().getValue("XAVATEST_DEFAULT_YEAR"));
Pour en apprendre plus sur les variables d'environnement, rendez-vous au chapitre 7 sur les contrôleurs.

Sélection SQL pure

Vous pouvez aussi écrire une requête de sélection complète pour récupérer les données :
@Tab(name="CompleteSelect",
 properties="number, description, family",
 baseCondition=
 "select" +
 " ${number}, ${description}, XAVATEST.FAMILY.DESCRIPTION " +
 "from " +
 " XAVATEST.SUBFAMILY, XAVATEST.FAMILY " +
 "where " +
 " XAVATEST.SUBFAMILY.FAMILY = " +
 " XAVATEST.FAMILY.NUMBER"
)
Utilisez ceci dans des cas extrêmes. Normalement, ce n'est pas nécessaire, et si vous voulez tout de même utiliser cette technique, l'utilisateur ne pourra pas personnaliser sa liste.

Tri par défaut

Finalement, définir le tri par défaut est très facile :
@Tab(name="Simple", properties="year, number, date",
 defaultOrder="${year} desc, ${number} desc"
)
Ceci est le tri initial spécifié et l'utilisateur peut choisir n'importe quel autre tri en cliquant sur l'en-tête de la colonne.

Default values for tabs at application level (new in v4m4)

Please, translate these section to French
You can define default values for all (or selected) @Tabs of your application at once. To do so, create a default-values-tabs.xml file in the xava folder of your application, just as the next example:
<?xml version = "1.0" encoding = "ISO-8859-1"?>
 
<!DOCTYPE tabs-default-values SYSTEM "dtds/tabs-default-values.dtd">
 
<tabs-default-values>
 
 <tab>
 <filter class="org.openxava.test.filters.ActiveYearFilter"/>
 <base-condition>${year} = ?</base-condition>
 
 <for-model model="Delivery"/>
 <for-model model="Invoice"/>
 </tab>
 
 <tab>
 <properties>year, number, date</properties>
 <default-order>${number} desc</default-order>
 
 <for-model model="Delivery"/>
 </tab>
 
 <tab>
 <filter class="org.openxava.filters.UserFilter"/>
 <base-condition>${user} = ?</base-condition>
 
 <except-for-model model="User"/>
 </tab>
 
 <tab>
 <default-order>${oid} asc</default-order>
 <for-all-models/>
 </tab>
 
</tabs-default-values>
The <tab/> element follows the syntax of XML Components for tabs. With the addition of <for-model/>, <except-for-model/> and <for-all-models/> used to apply the values to the tabs of the desired entities.
With this tab elements you define default values for the tabs of your entities, therefore the values used in the @Tabs defined in your entities always take preference over these ones.

Column summation (new in v4.1)

Please, translate this section to French
To show the sum of all the value of a column at the bottom of the list you only have to add the + symbol to the property name, as following:
@Tab( properties = "year, number, description, amount+" )
In this case the sum of the amount column will be shown just as in the next figure:
tab_en030.jpg
The summation is only allowed for not calculated numeric properties.

Choosing an editor (new in v4.6)

Please, translate this section to French
An editor is the actual code (usually a JSP) that displays the list to the user. By default, the editor OpenXava uses for displaying tabular data is a list with pagination, filtering, ordering and search, but you can specify your own editor to display a concrete tab using the atribute editor in @Tab.
For example, if you have a list of a Customer entities and you want to display it using a custom user interface, such as a row of cards, you can do it in this way:
@Tab ( name ="Cards", editor="CustomerCardList",
    properties="number, name, type, address.city, address.state.name"
)
In this case the CustomerCardList editor will be used for displaying/editing the tab data, instead of the default one. You must define your CustomerCardList editor in the xava/editors.xml file of your project:
<editor name="CustomerCardList" url="customerCardListEditor.jsp"/>
Also you have to write the JSP code for your editor in customerCardListEditor.jsp.
This feature is for changing the editor for a concrete tab in a concrete entity. If you want to change the editor for all tabs of a certain entity type at application level then it's better to configure it using xava/editors.xml file.
Learn more on Editors for tabs section of chapter 9.

Disabling customization

Please, translate this section to French
The user can customize the list adding, moving, removing columns and some more things:
tab_en040.jpg
If you do not want that your users customizing the list you can disable it at application level adding the next entry in xava.properties:
customizeList=false
If you want to disable the list customization for a specific list under certain circumstances you can do it by code:
public class MyAction extends TabBaseAction {
 
    public void execute() throws Exception {
        if (myCondition) {
            getTab().setCustomizeAllowed(false);
        }
        ...
    }
 
}
If you want to disable the customization for just a module, there is already a controller for that, called NoCustomizeList (new in v5.0). Use it when you define your module in application.xml (look at chapter 8) as following:
<module name="Warehouse">
    <model name="Warehouse"/>
    <controller name="Typical"/>
    <controller name="NoCustomizeList"/>
</module>
In this way, the Warehouse module does not allow the user to customize the list.